package com.atguigu.tingshu.album.service.impl;

import com.atguigu.tingshu.album.config.VodConstantProperties;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackStatMapper;
import com.atguigu.tingshu.album.service.AlbumInfoService;
import com.atguigu.tingshu.album.service.TrackInfoService;
import com.atguigu.tingshu.album.service.VodService;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.common.util.UploadFileUtil;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.album.TrackStat;
import com.atguigu.tingshu.query.album.TrackInfoQuery;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.album.AlbumTrackListVo;
import com.atguigu.tingshu.vo.album.TrackInfoVo;
import com.atguigu.tingshu.vo.album.TrackListVo;
import com.atguigu.tingshu.vo.album.TrackMediaInfoVo;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qcloud.vod.VodUploadClient;
import com.qcloud.vod.model.VodUploadRequest;
import com.qcloud.vod.model.VodUploadResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class TrackInfoServiceImpl extends ServiceImpl<TrackInfoMapper, TrackInfo> implements TrackInfoService {

	@Autowired
	private TrackInfoMapper trackInfoMapper;

	@Autowired
	private TrackStatMapper trackStatMapper;

	@Autowired
	private AlbumInfoMapper albumInfoMapper;

	@Autowired
	private VodConstantProperties vodConstantProperties;

	@Autowired
	private UserInfoFeignClient userInfoFeignClient;

	@Autowired
	private VodService vodService;

	@Autowired
	private AlbumInfoService albumInfoService;
	/**
	 * 上传声音
	 * @param file
	 * @return
	 */
	@Override
	public Map<String, Object> uploadTrack(MultipartFile file) {
		//创建map集合
		Map<String, Object> map = new HashMap<>();
		//获取路径
		String tempPath = UploadFileUtil.uploadTempPath(vodConstantProperties.getTempPath(),file);
		//初始化一个上传客户端对象
		VodUploadClient vodUploadClient = new VodUploadClient(vodConstantProperties.getSecretId(),vodConstantProperties.getSecretKey());
		//获取上传请求对象
		VodUploadRequest request  = new VodUploadRequest();
		request.setMediaFilePath(tempPath);

		//云点播： 不指定任务流不花钱   存储也花钱  SimpleAesEncryptPreset
		//
		//request.setProcedure("Your procedure Name");
		//调用上传方法
		try {
			VodUploadResponse response = vodUploadClient.upload(vodConstantProperties.getRegion(), request);
			log.info("Upload Filed ={}", response.getFileId());
			map.put("mediaFileId",response.getFileId());
			map.put("mediaUrl",response.getMediaUrl());
			//返回集合
			return map;
		} catch (Exception e) {
			//业务方进行异常处理
			log.error("Ipload Err",e);
			throw new GuiguException(ResultCodeEnum.FAIL);
		}
	}

	/**
	 * 保存声音
	 * @param trackInfoVo
	 * @param userId
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void saveTrackInfo(TrackInfoVo trackInfoVo, Long userId) {
		//track_info 声音主表
		//属性拷贝
		TrackInfo trackInfo = new TrackInfo();
		BeanUtils.copyProperties(trackInfoVo,trackInfo);
		trackInfo.setUserId(userId);
		//order_num 表示声音顺序号    必须是同一张专辑的
		//	select order_num from track_info where album_id = ? and is_deleted = 0 order by id desc limit 1;
		LambdaQueryWrapper<TrackInfo> wrapper = new LambdaQueryWrapper<>();
		wrapper.eq(TrackInfo::getAlbumId,trackInfoVo.getAlbumId())
				.orderByDesc(TrackInfo::getId)
				.last("limit 1")
				.select(TrackInfo::getOrderNum);
		//获取查询结果
		TrackInfo trackInfoQuery = trackInfoMapper.selectOne(wrapper);
		//判断查询对象是否为空
		/*if(trackInfoQuery != null){
			//不为空
			trackInfo.setOrderNum(trackInfoQuery.getOrderNum()+1);
		}else{
			//为空
			trackInfo.setOrderNum(1);
		}*/
		//使用三元运算符进行表示
		trackInfo.setOrderNum( null== trackInfoQuery ? 1 : trackInfoQuery.getOrderNum()+1);
		//	media_duration media_url media_size media_type 需要通过 media_file_id 从云点播获取声音对象
		//	调用方法:
		TrackMediaInfoVo trackMediaInfoVo = vodService.getMediaInfo(trackInfoVo.getMediaFileId());
		trackInfo.setMediaDuration(trackMediaInfoVo.getDuration());
		trackInfo.setMediaUrl(trackMediaInfoVo.getMediaUrl());
		trackInfo.setMediaSize(trackMediaInfoVo.getSize());
		trackInfo.setMediaType(trackMediaInfoVo.getType());

		//保存 数据
		trackInfoMapper.insert(trackInfo);

		//track_stat
		this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_PLAY);
		this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_COLLECT);
		this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_PRAISE);
		this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_COMMENT);

		//修改专辑表中的专辑声音总数   include_track_count的数据
		//声明专辑对象
		AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfoVo.getAlbumId());
		albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount()+1);
		albumInfoMapper.updateById(albumInfo);
	}

	/**
	 * 保存声音统计数据
	 * @param trackId
	 * @param statPlay
	 */
	private void saveTrackStat(Long trackId, String statPlay) {
		//保存声音统计数据
		//创建一个   声音统计对象
		TrackStat trackStat = new TrackStat();
		//获取到声音统计id
		trackStat.setTrackId(trackId);
		//获取到统计类型
		trackStat.setStatType(statPlay);
		//获取到统计数量
		trackStat.setStatNum(0);
		//保存
		trackStatMapper.insert(trackStat);

	}

	/**
	 * 查询声音列表
	 * @param trackListVoPage
	 * @param trackInfoQuery
	 * @return
	 */
	@Override
	public IPage<TrackListVo> findUserTrackPage(Page<TrackListVo> trackListVoPage, TrackInfoQuery trackInfoQuery) {
		//调用mapper层方法
		return trackInfoMapper.selectUserTrackPage(trackListVoPage, trackInfoQuery);
	}

	/**
	 * 删除声音
	 * @param trackId
	 */
	@Override
	public void removeTrackInfo(Long trackId) {
		//根据专辑id 获取专辑对象
		TrackInfo trackInfo = trackInfoMapper.selectById(trackId);
		AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfo.getAlbumId());
		//  删除 track_info track_stat album_info.include_track_count
		//  is_deleted = 1 代表无效数据
		this.trackInfoMapper.deleteById(trackId);
		// 删除 track_stat 字段
		trackStatMapper.delete(new LambdaQueryWrapper<TrackStat>().eq(TrackStat::getTrackId,trackId));
		//修改专辑表中的专辑声音总数
		albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount()-1);
		//更新
		albumInfoMapper.updateById(albumInfo);
		//  更新序号只需要处理order_num 一个字段就可以了。
		//  update track_info set order_num = order_num - 1 where order_num > 52  and album_id = 1 and is_deleted = 0
		trackInfoMapper.updateOrderNum(trackInfo.getOrderNum(),trackInfo.getAlbumId());
		//删除声音对象
		vodService.deleteMedia(trackInfo.getMediaFileId());

	}

	/**
	 * 根据声音id查询声音对象
	 * @param trackId
	 * @return
	 */
	@Override
	public TrackInfo getTrackInfo(Long trackId) {
		//获取声音对象
		TrackInfo trackInfo = trackInfoMapper.selectById(trackId);
		//返回数据
		return trackInfo;
	}

	/**
	 * 修改声音
	 *
	 * @param trackId
	 * @param trackInfoVo
	 */
	@Override
	public void updateTrackInfo(Long trackId, TrackInfoVo trackInfoVo) {
		//  没有声音修改：直接修改trackInfo; 如果有声音修改. 改变声音大小，类型等数据.
		//  创建TrackInfo对象 this.getById(trackId); =
		TrackInfo trackInfo = this.getById(trackId);
		// TrackInfo trackInfo = new TrackInfo(); trackInfo.getAlbumId();
		//  先查询声音Id
		String mediaFileId = trackInfo.getMediaFileId();
		//  进行属性拷贝
		BeanUtils.copyProperties(trackInfoVo, trackInfo);
		//  根据原有声音Id 与 新的声音Id 是否相等，判断是否对声音做了修改
		//  trackInfo.getMediaFileId() 可能会产生空指针，如何解决 从数据库中获取即可
		if (!trackInfoVo.getMediaFileId().equals(mediaFileId)) {
			//  声音修改了; 从云点播平台获取声音对象
			TrackMediaInfoVo trackMediaInfoVo = vodService.getMediaInfo(trackInfoVo.getMediaFileId());
			trackInfo.setMediaUrl(trackMediaInfoVo.getMediaUrl());
			trackInfo.setMediaSize(trackMediaInfoVo.getSize());
			trackInfo.setMediaDuration(trackMediaInfoVo.getDuration());
			trackInfo.setMediaType(trackMediaInfoVo.getType());
			//  删除云点播的声音记录.
			vodService.deleteMedia(mediaFileId);
			//  原有声音统计信息... track_stat;
		}
		//  修改表数据.
		trackInfoMapper.updateById(trackInfo);
	}

	@Override
	public IPage<AlbumTrackListVo> findAlbumTrackPage(Page<AlbumTrackListVo> albumTrackListVoPage, Long albumId, Long userId) {
		//  复杂的业务逻辑. 根据专辑Id 获取到声音列表.
		IPage<AlbumTrackListVo> pageInfo = trackInfoMapper.selectAlbumTrackPage(albumTrackListVoPage, albumId);
		//  获取到专辑对象
		AlbumInfo albumInfo = this.albumInfoMapper.selectById(albumId);
		//  判断是否登录：
		if (null == userId) {
			//  当前未登录. 专辑类型分为 0101-免费、0102-vip免费、0103-付费
			//  判断专辑类型
			if (!albumInfo.getPayType().equals(SystemConstant.ALBUM_PAY_TYPE_FREE)) {
				//  0102-vip免费、0103-付费 除免费试听集数外，都需要显示付费标识！
				//  获取到当前专辑对应的免费集数.
				Integer tracksForFree = albumInfo.getTracksForFree();
				//  select * from track_info track where album_id = 1429 and is_deleted = 0 and order_num > 5 isShowPaidMark = true;
				pageInfo.getRecords()
						.stream()
						.filter(albumTrackListVo -> albumTrackListVo.getOrderNum() > tracksForFree)
						.forEach(albumTrackListVo -> albumTrackListVo.setIsShowPaidMark(true));
				//  返回数据
				return pageInfo;
			}
		} else {
			//  声明一个变量表示是否需要付费
			boolean isNeedPaid = false;
			//  当前处于登录状态,专辑的类型 0102-vip免费、0103-付费 用户的身份： vip 普通
			//  通过userId 获取用户身份.
			Result<UserInfoVo> userInfoVoResult = userInfoFeignClient.getUserInfoVo(userId);
			//  判断
			Assert.notNull(userInfoVoResult, "用户结果集为空");
			UserInfoVo userInfoVo = userInfoVoResult.getData();
			Assert.notNull(userInfoVo, "用户信息为空");
			if (albumInfo.getPayType().equals(SystemConstant.ALBUM_PAY_TYPE_VIPFREE)) {
				//  0102-vip免费 - 判断当前这个用户是否是vip！
				if ((userInfoVo.getIsVip() == 1 && userInfoVo.getVipExpireTime().before(new Date())) || userInfoVo.getIsVip() == 0) {
					//  需要付费
					isNeedPaid = true;
				}
			} else if (albumInfo.getPayType().equals(SystemConstant.ALBUM_PAY_TYPE_REQUIRE)) {
				//  需要付费
				isNeedPaid = true;
			}
			//  统一处理付费：
			if (isNeedPaid) {
				//  这个用户是否购买过专辑，或者购买过声音！
				//  获取需要付费的声音Id 列表.
				List<AlbumTrackListVo> albumTrackNeedPaidListVoList = pageInfo.getRecords()
						.stream()
						.filter(albumTrackListVo -> albumTrackListVo.getOrderNum() > albumInfo.getTracksForFree())
						.collect(Collectors.toList());
				//  获取对应的声音Id列表.
				List<Long> trackIdList = albumTrackNeedPaidListVoList.stream().map(AlbumTrackListVo::getTrackId).collect(Collectors.toList());
				//  需要远程调用。map中的key=trackId value=0或1 1：表示免费 0：表示付费。
				Result<Map<Long, Integer>> mapResult = userInfoFeignClient.userIsPaidTrack(albumId, trackIdList);
				Assert.notNull(mapResult, "返回结果集为空");
				Map<Long, Integer> map = mapResult.getData();
				Assert.notNull(map,"返回结果为空");
				//  循环遍历集合
				for (AlbumTrackListVo albumTrackListVo : albumTrackNeedPaidListVoList) {
					//  赋值数据
					albumTrackListVo.setIsShowPaidMark(map.get(albumTrackListVo.getTrackId()) == 1 ? false : true);
				}
			}
		}
		//  返回数据
		return pageInfo;
	}

	@Override
	public List<Map<String, Object>> findUserTrackPaidList(Long trackId) {
		// 获取声音对象
		TrackInfo trackInfo = trackInfoMapper.selectById(trackId);
		// 获取到专辑对象
		AlbumInfo albumInfo = albumInfoService.getById(trackInfo.getAlbumId());
		// 根据专辑Id 获取到声音Id集合
		Result<List<Long>> trackIdListResult = userInfoFeignClient.findUserPaidTrackList(trackInfo.getAlbumId());
		Assert.notNull(trackIdListResult,"专辑Id集合不为空");
		List<Long> trackIdList = trackIdListResult.getData();
		Assert.notNull(trackIdList,"声音专辑Id 不为空");

		// 获取当前专辑并且大于当前声音的全部声音Id
		List<TrackInfo> trackInfoList = trackInfoMapper.selectList(new LambdaQueryWrapper<TrackInfo>().eq(TrackInfo::getAlbumId, trackInfo.getAlbumId()).gt(TrackInfo::getOrderNum, trackInfo.getOrderNum()).select(TrackInfo::getId));
		List<Long> trackIdAllList = trackInfoList.stream().map(TrackInfo::getId).collect(Collectors.toList());
		// 去除已经支付的
		List<Long> trackIdNoReaptList = new ArrayList<>();
		if(CollectionUtils.isEmpty(trackIdList)) {
			trackIdNoReaptList = trackIdAllList;
		} else {
			// 获取没有购买的声音Id
			trackIdNoReaptList = trackIdAllList.stream().filter(itemId -> !trackIdList.contains(itemId)).collect(Collectors.toList());
		}

		// 构造声音分集购买数据列表
		List<Map<String, Object>> list = new ArrayList<>();
		// 需要付款的集数有 19
		// 本集
		if(trackIdNoReaptList.size() >= 0) {
			Map<String, Object> map = new HashMap<>();
			map.put("name", "本集");
			map.put("price", albumInfo.getPrice());
			map.put("trackCount", 0);
			list.add(map);
		}

		//后10集
		if(trackIdNoReaptList.size() > 0 && trackIdNoReaptList.size() <= 10) {
			Map<String, Object> map = new HashMap<>();
			int count = trackIdNoReaptList.size();
			BigDecimal price = albumInfo.getPrice().multiply(new BigDecimal(count));
			map.put("name", "后"+trackIdNoReaptList.size()+"集");
			map.put("price", price);
			map.put("trackCount", count);
			list.add(map);
		}
		// 19
		if(trackIdNoReaptList.size() > 10) {
			Map<String, Object> map = new HashMap<>();
			BigDecimal price = albumInfo.getPrice().multiply(new BigDecimal(10));
			map.put("name", "后10集");
			map.put("price", price);
			map.put("trackCount", 10);
			list.add(map);
		}
		// 后20集
		if(trackIdNoReaptList.size() > 10 && trackIdNoReaptList.size() <= 20) {
			Map<String, Object> map = new HashMap<>();
			int count = trackIdNoReaptList.size();
			BigDecimal price = albumInfo.getPrice().multiply(new BigDecimal(count));
			map.put("name", "后"+count+"集");
			map.put("price", price);
			map.put("trackCount", count);
			list.add(map);
		}
		if(trackIdNoReaptList.size() > 20) {
			Map<String, Object> map = new HashMap<>();
			BigDecimal price = albumInfo.getPrice().multiply(new BigDecimal(20));
			map.put("name", "后20集");
			map.put("price", price);
			map.put("trackCount", 20);
			list.add(map);
		}

		//后30集
		if(trackIdNoReaptList.size() > 20 && trackIdNoReaptList.size() <= 30) {
			Map<String, Object> map = new HashMap<>();
			int count = trackIdNoReaptList.size();
			BigDecimal price = albumInfo.getPrice().multiply(new BigDecimal(count));
			map.put("name", "后"+count+"集");
			map.put("price", price);
			map.put("trackCount", count);
			list.add(map);
		}
		if(trackIdNoReaptList.size() > 30) {
			Map<String, Object> map = new HashMap<>();
			BigDecimal price = albumInfo.getPrice().multiply(new BigDecimal(30));
			map.put("name", "后30集");
			map.put("price", price);
			map.put("trackCount", 30);
			list.add(map);
		}

		//后50集
		if(trackIdNoReaptList.size() > 30 && trackIdNoReaptList.size() <= 50) {
			Map<String, Object> map = new HashMap<>();
			int count = trackIdNoReaptList.size();
			BigDecimal price = albumInfo.getPrice().multiply(new BigDecimal(count));
			map.put("name", "后"+count+"集");
			map.put("price", price);
			map.put("trackCount", count);
			list.add(map);
		}
		// 最多购买50集;
		if(trackIdNoReaptList.size() > 50) {
			Map<String, Object> map = new HashMap<>();
			BigDecimal price = albumInfo.getPrice().multiply(new BigDecimal(50));
			map.put("name", "后50集");
			map.put("price", price);
			map.put("trackCount", 50);
			list.add(map);
		}
		return list;
	}

	@Override
	public List<TrackInfo> findPaidTrackInfoList(Long trackId, Integer trackCount) {
		// 根据声音Id 获取到声音对象
		TrackInfo trackInfo = this.getById(trackId);
		Assert.notNull(trackInfo,"声音对象不能为空");

		// 获取已支付的声音id列表
		Result<List<Long>> trackIdListResult = userInfoFeignClient.findUserPaidTrackList(trackInfo.getAlbumId());
		Assert.notNull(trackIdListResult);
		List<Long> trackIdList = trackIdListResult.getData();
		Assert.notNull(trackIdList);
		// 声明一个声音对象集合
		List<TrackInfo> trackInfoList = new ArrayList<>();
		if (trackCount>0){
			// 构建查询条件
			LambdaQueryWrapper<TrackInfo> trackInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
			trackInfoLambdaQueryWrapper.eq(TrackInfo::getAlbumId,trackInfo.getAlbumId());
			trackInfoLambdaQueryWrapper.gt(TrackInfo::getOrderNum,trackInfo.getOrderNum());
			trackInfoLambdaQueryWrapper.orderByAsc(TrackInfo::getOrderNum);
			if (!CollectionUtils.isEmpty(trackIdList)){
				trackInfoLambdaQueryWrapper.notIn(TrackInfo::getId,trackIdList);
			}
			trackInfoLambdaQueryWrapper.last("limit "+trackCount);
			trackInfoList = this.list(trackInfoLambdaQueryWrapper);
		} else {
			trackInfoList.add(trackInfo);
		}
		// 返回当前集合对象
		return trackInfoList;
	}


}
